package com.ocom.nettyxf.MyMessage;

import com.ocom.common.utils.StringUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhuhui
 * @version 2.0
 * @date 2023年6月8日13:42:05
 * 处理十进制字符串 自定义解码器 根据包头包尾处理粘包断包
 */
public class MyMessageDecoder extends ByteToMessageDecoder {
	// 存放 IP 以及每个IP 对应的断包
	private Map<String, String> histiry = new HashMap<>();
	// 包头
	public static final String START = "CAAC";
	public static final String END = "ACCA";

	@Override
	protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) {
		String msIp = ctx.channel().remoteAddress().toString().substring(1);
		//创建字节数组,buffer.readableBytes可读字节长度
		byte[] b = new byte[buffer.readableBytes()];
		//复制内容到字节数组b
		buffer.readBytes(b);
		//字节数组转字符串
		String msg = bytesToHexString(b);
		// 处理数据
		// 以包头开头 包尾结束且第一次出现的次数跟最后依次出现的次数相同 说明不包没问题 good
		if (msg.startsWith(START) && msg.endsWith(END) && msg.indexOf(END) == msg.lastIndexOf(END)) {
			out.add(msg);
		} else {
			// 处理年粘包 断包 问题
			List<String> list = subStringList(msg, msIp);
			for (String str : list) {
				out.add(str);
			}
		}
	}
	// 转十禁止
	public String bytesToHexString(byte[] bArray) {
		StringBuffer sb = new StringBuffer(bArray.length);
		String sTemp;
		for (int i = 0; i < bArray.length; i++) {
			sTemp = Integer.toHexString(0xFF & bArray[i]);
			if (sTemp.length() < 2)
				sb.append(0);
			sb.append(sTemp.toUpperCase());
		}
		return sb.toString();
	}

	/**
	 * 处理粘包 断包
	 * @param msg  收到的字符串
	 * @param msIP 根据IP 根据卡护短IP 区分
	 * @return
	 */
	public List<String> subStringList(String msg, String msIP) {
		List<String> list = new ArrayList<>();
		// 处理粘包  说明粘包
		if (msg.startsWith(START) && msg.endsWith(END)) {
			//分割就行
			String[] msgs = msg.split(END+START);
			for (int i =0;i<msgs.length;i++){
				if(i==0){
					list.add(msgs[i]+END);
				}else if(i+1==msgs.length){
					list.add(START+msgs[i]);
				}else{
					list.add(START+msgs[i]+END);
				}
			}
			return list;
		} else {
			// 断包信息处理  获取断包中头所在索引
			int begin = msg.indexOf(START);
			// 根据   ip 获取缓存数据
			String eachData = histiry.get(msIP) == null ? "" : histiry.get(msIP);
			// ① 没有头或者包头在索引大于0的位置
			if (begin == -1 || begin > 0) {
				// 如果缓存以开头开始 放到缓存处理
				if (eachData.startsWith(START)) {
					histiry.put(msIP, eachData + msg);
				} else if (begin != -1) {
					//走到这里说明缓存不是以开头开始 丢弃前半截数据
					histiry.put(msIP, msg.substring(begin));
				}
				// ② 有头  且索引0
			} else if (begin == 0) {
				// 直接替换缓存
				histiry.put(msIP, msg);
			}
			//  从缓存拿出组合的断包
			String sdata = histiry.get(msIP) == null ? "" : histiry.get(msIP);
			if(StringUtil.isEmpty(sdata)){
//				System.out.println(list);
//				System.out.println("end");
				return list;
			}
			if(!sdata.startsWith(START)){
				// 删除缓存
				histiry.remove(msIP);
//				System.out.println("end");
				return list;
			}
			if (sdata.startsWith(START) && sdata.endsWith(END) && sdata.indexOf(END) == sdata.lastIndexOf(END)) {
				list.add(sdata);
//				System.out.println(list);
//				System.out.println("end");
				return list;
			}else{
				String[] echeDatas = sdata.split(END);
				//缓存中保证数据是以开头开头 以结尾结尾
				if (echeDatas != null && echeDatas.length>0) {
					for (int i = 0; i < echeDatas.length - 1; i++) {
						//  echeDatas  至少有两个 针对最后一个判断
						list.add(echeDatas[i]+END);
					}
					if (sdata.endsWith(END)) {
						// 如果缓存中存在完整的一条数据  (有头有包)
						list.add(echeDatas[echeDatas.length - 1]+END);
						// 删除缓存
						histiry.remove(msIP);
					} else if (echeDatas.length > 0 && echeDatas[echeDatas.length - 1].startsWith(START)) {
						// 说明缓存中不是完整的包
						// 替换缓存
						histiry.put(msIP, echeDatas[echeDatas.length - 1]);
					} else {
						// 其他任何情况 清空
						histiry.remove(msIP);
					}
				}
			}
//			System.out.println(list);
//			System.out.println(histiry.get(msIP));
			return list;
		}
	}

}
